﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Xsl;
using System.IO;
using System.Xml;
using Microsoft.SharePoint;
using System.Net;
using System.Web;
using System.Collections.Specialized;

namespace SharePointPowerToys
{
    public class Helpers
    {
        #region TransformLoad
        /// <summary>
        /// TransformLoad
        /// </summary>
        /// <param name="transformFileUri"></param>
        /// <returns></returns>
        public static XslCompiledTransform TransformLoad(string transformFileUri)
        {
            return TransformLoad(transformFileUri, null, null);
        }

        /// <summary>
        /// TransformLoad
        /// </summary>
        /// <param name="transformFileUri"></param>
        /// <returns></returns>
        public static XslCompiledTransform TransformLoad(string transformFileUri, string username, string password)
        {
            var xslTransform = new XslCompiledTransform(false);
            string xslFile = string.Empty;
            if (!transformFileUri.StartsWith("<"))
            {
                xslFile = GetFile(transformFileUri, username, password);
            }
            else
            {
                xslFile = transformFileUri;
            }

            if (!String.IsNullOrEmpty(xslFile))
            {
                var sr = new StringReader(xslFile);
                try
                {
                    var xsltSettings = new XsltSettings { EnableScript = true };
                    var xmlResolver = new XmlUrlResolver();

                    XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
                    xmlReaderSettings.ProhibitDtd = false;

                    var xmlReader = XmlReader.Create(sr, xmlReaderSettings);
                    xslTransform.Load(xmlReader, xsltSettings, xmlResolver);
                }
                //catch { }
                catch (Exception ex)
                {
                    throw new Exception(String.Concat("Error in TransformLoad - ", ex.Message));
                }
                finally
                {
                    sr.Close();
                }
            }
            return xslTransform;
        }
        #endregion

        #region TransformGetString

        public static string TransformGetString(string xsl, string xslUsername, string xslPassword, string xml, string xmlUsername, string xmlPassword)
        {
            string results = string.Empty;
            XslCompiledTransform xslTransform = TransformLoad(xsl, xslUsername, xslPassword);
            var ms = new MemoryStream();
            var xmlTextWriter = new XmlTextWriter(ms, Encoding.ASCII);
            var rd = new StreamReader(ms);
            var sr = new StringReader(xml);
            try
            {
                xslTransform.Transform(XmlReader.Create(sr), null, xmlTextWriter);
                ms.Position = 0;
                results = rd.ReadToEnd();
            }
            //catch { }
            catch (Exception ex)
            {
                results = String.Concat("Error in TransformGetString: ", ex.Message);
            }
            finally
            {
                sr.Close();
                rd.Close();
                xmlTextWriter.Close();
                ms.Close();
            }
            return results;
        }

        /// <summary>
        /// TransformGetString
        /// </summary>
        /// <param name="xslTransform"></param>
        /// <param name="xmlReader"></param>
        /// <returns></returns>
        public static string TransformGetString(XslCompiledTransform xslTransform, XmlReader xmlReader)
        {
            string results = string.Empty;
            var ms = new MemoryStream();
            var xmlTextWriter = new XmlTextWriter(ms, Encoding.ASCII);
            var rd = new StreamReader(ms);
            try
            {
                xslTransform.Transform(xmlReader, null, xmlTextWriter);
                ms.Position = 0;
                results = rd.ReadToEnd();
            }
            //catch {}
            catch (Exception ex)
            {
                results = String.Concat("Error in TransformGetString: ", ex.Message);
            }
            finally
            {
                rd.Close();
                xmlTextWriter.Close();
                ms.Close();
            }
            return results;
        }
        #endregion

        #region GetFile
        /// <summary>
        /// GetFile
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public static string GetFile(string uri, string username, string password)
        {
            var results = string.Empty;
            if (uri.ToLower().StartsWith("http"))
            {
                results = GetWebFile(uri, username, password, true);
            }
            if (results == string.Empty)
            {
                results = GetSpFile(uri);
            }
            return results;
        }
        #endregion

        #region GetSpFile
        /// <summary>
        /// GetSpFile
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetSpFile(string fileName)
        {
            return GetSpFile(null, null, null, fileName);
        }

        /// <summary>
        /// GetSpFile
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetSpFile(string folderName, string fileName)
        {
            return GetSpFile(null, null, folderName, fileName);
        }

        /// <summary>
        /// GetSpFile
        /// </summary>
        /// <param name="listName"></param>
        /// <param name="folderName"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetSpFile(string listName, string folderName, string fileName)
        {
            return GetSpFile(null, listName, folderName, fileName);
        }

        /// <summary>
        /// GetSpFile
        /// </summary>
        /// <param name="siteUrl"></param>
        /// <param name="listName"></param>
        /// <param name="folderName"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetSpFile(string siteUrl, string listName, string folderName, string fileName)
        {
            string contents = string.Empty;
            if (fileName == string.Empty)
            {
                return contents;
            }
            try
            {
                //Stream fileStream = new MemoryStream();
                if (fileName.StartsWith("http"))
                {
                    try
                    {
                        SPSecurity.RunWithElevatedPrivileges(() =>
                        {
                            using (var portalSite = new SPSite(fileName))
                            {
                                var web = portalSite.OpenWeb();
                                var file = web.GetFile(fileName);
                                var content = file.OpenBinary();
                                var enc = new ASCIIEncoding();
                                contents = enc.GetString(content);
                            }
                        });
                    }
                    catch { }
                }
                else
                {
                    if (String.IsNullOrEmpty(siteUrl))
                    {
                        siteUrl = HttpContext.Current.Request.Url.ToString();
                    }

                    if (String.IsNullOrEmpty(listName))
                    {
                        listName = "Style Library";
                    }

                    if (String.IsNullOrEmpty(folderName))
                    {
                        folderName = "XSL Style Sheets";
                    }

                    SPSecurity.RunWithElevatedPrivileges(() =>
                    {
                        using (var site = new SPSite(siteUrl))
                        {
                            using (SPWeb web = site.OpenWeb())
                            {
                                SPDocumentLibrary library = null;
                                try
                                {
                                    library = (SPDocumentLibrary)web.Lists[listName];
                                }
                                catch { }

                                if (library != null)
                                {
                                    string libraryRelativePath = library.RootFolder.SubFolders[folderName].ServerRelativeUrl;
                                    string libraryPath = site.MakeFullUrl(libraryRelativePath);
                                    string documentPath = libraryPath + "/" + fileName;

                                    contents = web.GetFileAsString(documentPath);
                                }
                            }
                        }
                    });
                }
            }
            catch { }
            
            return contents;
        }
        #endregion

        #region Clean Urls
        public static string GetWebUrlFromUrl(string requestUrl)
        {
            string url = string.Empty;
            using (var site = new SPSite(requestUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    url = web.Url;
                }
            }
            return url;
        }

        public static string GetCleanUrl(string url)
        {
            string cleanUrl = string.Empty;

            cleanUrl = url.Replace("http://", "");
            cleanUrl = cleanUrl.Replace("https://", "");
            cleanUrl = cleanUrl.Replace("/default.aspx", "");
            cleanUrl = cleanUrl.Replace("/", "_");
            return cleanUrl;
        }
        #endregion

        #region GetWebFile
        /// <summary>
        /// GetWebFile
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public static string GetWebFile(string uri)
        {
            return GetWebFile(uri, null, null, false);
        }

        /// <summary>
        /// GetWebFile
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="ignoreErrors"></param>
        /// <returns></returns>
        public static string GetWebFile(string uri, string username, string password, bool ignoreErrors)
        {
            const int bufSizeMax = 65536;
            // max read buffer size conserves memory
            const int bufSizeMin = 8192;
            // min size prevents numerous small reads
            var sb = new StringBuilder();
            // A WebException is thrown if HTTP request fails
            try
            {
                SPSecurity.RunWithElevatedPrivileges(() =>
                {
                    // Create an HttpWebRequest using WebRequest.Create (see .NET docs)!
                    var request = WebRequest.Create(uri);
                    //Use the credentials of the app pool who certainly has access to what ever it is we need.
                    if (String.IsNullOrEmpty(username) && String.IsNullOrEmpty(password))
                    {
                        request.Credentials = CredentialCache.DefaultCredentials;
                    }
                    else
                    {
                        request.Credentials = new NetworkCredential(username, password);
                    }

                    // Execute the request and obtain the response stream
                    using (var response = request.GetResponse())
                    {
                        using (Stream responseStream = response.GetResponseStream())
                        {
                            // Content-Length header is not trustable, but makes a good hint.
                            // Responses longer than int size will throw an exception here!
                            var length = (int)response.ContentLength;
                            // Use Content-Length if between bufSizeMax and bufSizeMin
                            var bufSize = bufSizeMin;
                            if (length > bufSize)
                            {
                                bufSize = length > bufSizeMax ? bufSizeMax : length;
                            }
                            // Allocate buffer and StringBuilder for reading response
                            var buf = new byte[bufSize];
                            sb = new StringBuilder(bufSize);
                            // Read response stream until end
                            while ((length = responseStream.Read(buf, 0, buf.Length)) != 0)
                            {
                                sb.Append(Encoding.UTF8.GetString(buf, 0, length));
                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                if (!ignoreErrors)
                {
                    sb.Append(ex.Message);
                }
            }
            return sb.ToString().Trim();
        }
        #endregion

        #region Tokens
        public static NameValueCollection SwapTokensGetDefaultTokens()
        {
            NameValueCollection tokens = new NameValueCollection();

            tokens.Add("{Url}", GetCleanUrl(HttpContext.Current.Request.Url.ToString().Remove(0, SPContext.Current.Site.RootWeb.Url.Length + 1)));
            tokens.Add("ServerVariable(URL)", HttpContext.Current.Request.Url.ToString());
            tokens.Add("{SiteUrl}", GetCleanUrl(SPContext.Current.Web.Url.Remove(0, SPContext.Current.Site.RootWeb.Url.Length + 1)));
            //contents = SwapToken(contents, "{WebPartTitle}", SPContext.Current);

            return tokens;
        }

        public static string SwapTokens(string contents, NameValueCollection tokens)
        {
            foreach (var token in tokens.AllKeys)
            {
                contents = SwapToken(contents, token, tokens[token]);
            }
            return contents;
        }

        public static string SwapToken(string contents, string token, string value)
        {
            if (contents.Contains(token))
            {
                contents = contents.Replace(token, value);
                contents = string.Concat(contents, "\r\n<!--Wrote to contents:", token, value, "-->\r\n");
            }
            return contents;
        }
        #endregion
    }
}
